From eab3ef31455b8ce2c410d2c45240a77bdd9f5bd2 Mon Sep 17 00:00:00 2001 From: Kristian Rietveld Date: Wed, 12 Sep 2007 17:13:24 +0000 Subject: [PATCH] Fixes #426246. 2007-09-12 Kristian Rietveld Fixes #426246. * gdk/gdk.symbols: * gdk/gdkwindow.[ch] (gdk_window_freeze_toplevel_updates_libgtk_only), (gdk_window_thaw_toplevel_updates_libgtk_only): new functions to freeze a toplevel window and all its descendants. To be made public in 2.14, (gdk_window_schedule_update): return if toplevel is frozen, (gdk_window_process_all_updates): defer processing updates if toplevel is frozen. * gtk/gtkwindow.c (gtk_window_configure_event): directly size allocate for override redirect windows, freeze toplevel and descendants otherwise and wait until resizing is done. svn path=/trunk/; revision=18802 --- ChangeLog | 18 ++++++++++++ gdk/gdk.symbols | 2 ++ gdk/gdkwindow.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++-- gdk/gdkwindow.h | 5 ++++ gtk/gtkwindow.c | 68 +++++++++++++++++++++++++++++---------------- 5 files changed, 140 insertions(+), 26 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5aba8a8bb3..f9da226777 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2007-09-12 Kristian Rietveld + + Fixes #426246. + + * gdk/gdk.symbols: + * gdk/gdkwindow.[ch] + (gdk_window_freeze_toplevel_updates_libgtk_only), + (gdk_window_thaw_toplevel_updates_libgtk_only): new functions + to freeze a toplevel window and all its descendants. To be made + public in 2.14, + (gdk_window_schedule_update): return if toplevel is frozen, + (gdk_window_process_all_updates): defer processing updates if toplevel + is frozen. + + * gtk/gtkwindow.c (gtk_window_configure_event): directly size + allocate for override redirect windows, freeze toplevel and + descendants otherwise and wait until resizing is done. + 2007-09-11 Michael Natterer * gtk/gtkfilechooserbutton.c: remove useless member "has_title" diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols index ef801d3e34..d7962109fe 100644 --- a/gdk/gdk.symbols +++ b/gdk/gdk.symbols @@ -649,6 +649,7 @@ gdk_window_constrain_size gdk_window_destroy gdk_window_end_paint gdk_window_foreign_new +gdk_window_freeze_toplevel_updates_libgtk_only gdk_window_freeze_updates gdk_window_get_children gdk_window_get_internal_paint_info @@ -673,6 +674,7 @@ gdk_window_process_updates gdk_window_remove_filter gdk_window_set_debug_updates gdk_window_set_user_data +gdk_window_thaw_toplevel_updates_libgtk_only gdk_window_thaw_updates gdk_window_set_composited #endif diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 2028693cb0..fe4e7f674a 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -2290,10 +2290,22 @@ gdk_window_update_idle (gpointer data) return FALSE; } +static gboolean +gdk_window_is_toplevel_frozen (GdkWindow *window) +{ + GdkWindowObject *toplevel; + + toplevel = (GdkWindowObject *)gdk_window_get_toplevel (window); + + return toplevel->update_and_descendants_freeze_count > 0; +} + static void gdk_window_schedule_update (GdkWindow *window) { - if (window && GDK_WINDOW_OBJECT (window)->update_freeze_count) + if (window && + (GDK_WINDOW_OBJECT (window)->update_freeze_count || + gdk_window_is_toplevel_frozen (window))) return; if (!update_idle) @@ -2423,7 +2435,8 @@ gdk_window_process_all_updates (void) { GdkWindowObject *private = (GdkWindowObject *)tmp_list->data; - if (private->update_freeze_count) + if (private->update_freeze_count || + gdk_window_is_toplevel_frozen (tmp_list->data)) update_windows = g_slist_prepend (update_windows, private); else gdk_window_process_updates_internal (tmp_list->data); @@ -2471,7 +2484,9 @@ gdk_window_process_updates (GdkWindow *window, return; } - if (private->update_area && !private->update_freeze_count) + if (private->update_area && + !private->update_freeze_count && + !gdk_window_is_toplevel_frozen (window)) { gdk_window_process_updates_internal (window); update_windows = g_slist_remove (update_windows, window); @@ -2815,6 +2830,58 @@ gdk_window_thaw_updates (GdkWindow *window) gdk_window_schedule_update (window); } +/** + * gdk_window_freeze_toplevel_updates_libgtk_only: + * @window: a #GdkWindow + * + * Temporarily freezes a window and all its descendants such that it won't + * receive expose events. The window will begin receiving expose events + * again when gdk_window_thaw_toplevel_updates_libgtk_only() is called. If + * gdk_window_freeze_toplevel_updates_libgtk_only() + * has been called more than once, + * gdk_window_thaw_toplevel_updates_libgtk_only() must be called + * an equal number of times to begin processing exposes. + * + * This function is not part of the GDK public API and is only + * for use by GTK+. + **/ +void +gdk_window_freeze_toplevel_updates_libgtk_only (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (private->window_type != GDK_WINDOW_CHILD); + + private->update_and_descendants_freeze_count++; +} + +/** + * gdk_window_thaw_toplevel_updates_libgtk_only: + * @window: a #GdkWindow + * + * Thaws a window frozen with + * gdk_window_freeze_toplevel_updates_libgtk_only(). + * + * This function is not part of the GDK public API and is only + * for use by GTK+. + **/ +void +gdk_window_thaw_toplevel_updates_libgtk_only (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (private->window_type != GDK_WINDOW_CHILD); + g_return_if_fail (private->update_and_descendants_freeze_count > 0); + + private->update_and_descendants_freeze_count--; + + gdk_window_schedule_update (window); +} + /** * gdk_window_set_debug_updates: * @setting: %TRUE to turn on update debugging diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h index d50d3e6c9a..3e169c4398 100644 --- a/gdk/gdkwindow.h +++ b/gdk/gdkwindow.h @@ -298,6 +298,8 @@ struct _GdkWindowObject guint shaped : 1; GdkEventMask event_mask; + + guint update_and_descendants_freeze_count; }; struct _GdkWindowObjectClass @@ -605,6 +607,9 @@ GdkRegion *gdk_window_get_update_area (GdkWindow *window); void gdk_window_freeze_updates (GdkWindow *window); void gdk_window_thaw_updates (GdkWindow *window); +void gdk_window_freeze_toplevel_updates_libgtk_only (GdkWindow *window); +void gdk_window_thaw_toplevel_updates_libgtk_only (GdkWindow *window); + void gdk_window_process_all_updates (void); void gdk_window_process_updates (GdkWindow *window, gboolean update_children); diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 590bf6bf12..78b34011c6 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -4819,7 +4819,10 @@ gtk_window_configure_event (GtkWidget *widget, */ if (window->configure_request_count > 0) - window->configure_request_count -= 1; + { + window->configure_request_count -= 1; + gdk_window_thaw_toplevel_updates_libgtk_only (widget->window); + } /* As an optimization, we avoid a resize when possible. * @@ -6053,28 +6056,47 @@ gtk_window_move_resize (GtkWindow *window) new_request.width, new_request.height); } - /* Increment the number of have-not-yet-received-notify requests */ - window->configure_request_count += 1; - - /* for GTK_RESIZE_QUEUE toplevels, we are now awaiting a new - * configure event in response to our resizing request. - * the configure event will cause a new resize with - * ->configure_notify_received=TRUE. - * until then, we want to - * - discard expose events - * - coalesce resizes for our children - * - defer any window resizes until the configure event arrived - * to achieve this, we queue a resize for the window, but remove its - * resizing handler, so resizing will not be handled from the next - * idle handler but when the configure event arrives. - * - * FIXME: we should also dequeue the pending redraws here, since - * we handle those ourselves upon ->configure_notify_received==TRUE. - */ - if (container->resize_mode == GTK_RESIZE_QUEUE) - { - gtk_widget_queue_resize (widget); - _gtk_container_dequeue_resize_handler (container); + if (window->type == GTK_WINDOW_POPUP) + { + GtkAllocation allocation; + + /* Directly size allocate for override redirect (popup) windows. */ + allocation.width = new_request.width; + allocation.height = new_request.height; + + gtk_widget_size_allocate (widget, &allocation); + + gdk_window_process_updates (widget->window, TRUE); + + if (container->resize_mode == GTK_RESIZE_QUEUE) + gtk_widget_queue_draw (widget); + } + else + { + /* Increment the number of have-not-yet-received-notify requests */ + window->configure_request_count += 1; + gdk_window_freeze_toplevel_updates_libgtk_only (widget->window); + + /* for GTK_RESIZE_QUEUE toplevels, we are now awaiting a new + * configure event in response to our resizing request. + * the configure event will cause a new resize with + * ->configure_notify_received=TRUE. + * until then, we want to + * - discard expose events + * - coalesce resizes for our children + * - defer any window resizes until the configure event arrived + * to achieve this, we queue a resize for the window, but remove its + * resizing handler, so resizing will not be handled from the next + * idle handler but when the configure event arrives. + * + * FIXME: we should also dequeue the pending redraws here, since + * we handle those ourselves upon ->configure_notify_received==TRUE. + */ + if (container->resize_mode == GTK_RESIZE_QUEUE) + { + gtk_widget_queue_resize (widget); + _gtk_container_dequeue_resize_handler (container); + } } } else -- 2.30.2